package org.glassunit.core.deploy;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

/**
 * Jar file base module.
 * @author Frederic Müller
 */
public class JarModule extends Module {

    private final JarFile root;

    /**
     * Creates a new jar module for the given jar file.
     * The module's name is determined by the file name
     * @param file jar file
     */
    public JarModule(final File file) {
        this(file.getName(), file);
    }

    /**
     * Creates a new jar module for the given jar file with the given name.
     * @param name module name
     * @param file jar file
     */
    public JarModule(final String name, final File file) {
        super(name);
        try {
            this.root = new JarFile(file);
        } catch (final IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public Set<String> getFiles() {
        final Set<String> items = new HashSet<String>();
        items.addAll(getFiles(root));
        items.addAll(super.getFiles());

        return items;
    }

    /**
     * Retrieves all files in this jar.
     * @param jarFile jar file
     * @return list of files
     */
    private Set<String> getFiles(final JarFile jarFile) {
        final Set<String> items = new HashSet<String>();
        final Enumeration<JarEntry> entries = jarFile.entries();

        while (entries.hasMoreElements()) {
            final JarEntry entry = entries.nextElement();
            if (!entry.isDirectory()) {
                items.add(entry.getName());
            }
        }
        return items;
    }

    @Override
    public Set<String> getDirectories() {
        final Set<String> items = new HashSet<String>();
        items.addAll(getDirectories(root));
        items.addAll(super.getDirectories());
        return items;
    }

    /**
     * Retrieves all directories in this jar.
     * @param jarFile jar file
     * @return list of directories
     */
    private Set<String> getDirectories(final JarFile jarFile) {
        final Set<String> items = new HashSet<String>();
        final Enumeration<JarEntry> entries = jarFile.entries();

        while (entries.hasMoreElements()) {
            final JarEntry entry = entries.nextElement();
            if (entry.isDirectory()) {
                items.add(entry.getName());
            }
        }
        return items;
    }

    @Override
    public InputStream getFile(final String filename) throws IOException {
        final ZipEntry entry = root.getEntry(filename);

        if (entry != null) {
            return root.getInputStream(entry);
        } else {
            return super.getFile(filename);
        }
    }

    @Override
    public Long getFileSize(final String filename) {
        final ZipEntry entry = root.getEntry(filename);

        if (entry != null) {
            return entry.getSize();
        } else {
            return super.getFileSize(filename);
        }
    }

    @Override
    public boolean exists(final String filename) {
        final ZipEntry entry = root.getEntry(filename);
        if (entry != null) {
            return true;
        }
        return super.exists(filename);
    }

    @Override
    public void close() throws IOException {
        root.close();
        super.close();
    }


}
